/******************************************************************************* * Copyright (c) 2009 EclipseSource and others. All rights reserved. This * program and the accompanying materials are made available under the terms of * the Eclipse Public License v1.0 which accompanies this distribution, and is * available at http://www.eclipse.org/legal/epl-v10.html * * Contributors: * EclipseSource - initial API and implementation *******************************************************************************/ package org.eclipse.rap.ui.interactiondesign; import java.util.ArrayList; import java.util.List; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtensionPoint; import org.eclipse.core.runtime.IExtensionRegistry; import org.eclipse.core.runtime.Platform; import org.eclipse.jface.action.IContributionItem; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.IToolBarManager; import org.eclipse.jface.internal.provisional.action.IToolBarManager2; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.rap.ui.interactiondesign.internal.ConfigurableStackProxy; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.ui.IActionBars; import org.eclipse.ui.IViewPart; import org.eclipse.ui.IViewReference; import org.eclipse.ui.IViewSite; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.internal.DefaultStackPresentationSite; import org.eclipse.ui.internal.LayoutPart; import org.eclipse.ui.internal.PartPane; import org.eclipse.ui.internal.ViewPane; import org.eclipse.ui.internal.presentations.PresentablePart; import org.eclipse.ui.internal.util.PrefUtil; import org.eclipse.ui.part.ViewPart; import org.eclipse.ui.plugin.AbstractUIPlugin; import org.eclipse.ui.preferences.ScopedPreferenceStore; import org.eclipse.ui.presentations.IPartMenu; import org.eclipse.ui.presentations.IPresentablePart; import org.eclipse.ui.presentations.IStackPresentationSite; import org.eclipse.ui.presentations.StackPresentation; /** * This represents an object, which extends the original <code> * {@link StackPresentation}</code>. * <p> * You can do everything with this as you can do with the original one. It * just provides more methods for making a StackPresentation configurable. * </p> * * @see StackPresentation * @since 1.2 */ public abstract class ConfigurableStack extends StackPresentation { private static final String CONFIG_ACTION_NAME = "actionClass"; private static IStackPresentationSite siteDummy = new IStackPresentationSite() { public void addSystemActions( final IMenuManager menuManager ) { } public void close( final IPresentablePart[] toClose ) { } public void dragStart( final IPresentablePart beingDragged, final Point initialPosition, final boolean keyboard ) { } public void dragStart( final Point initialPosition, final boolean keyboard ) { } public void flushLayout() { } public IPresentablePart[] getPartList() { return null; } public String getProperty( final String id ) { return null; } public IPresentablePart getSelectedPart() { return null; } public int getState() { return 0; } public boolean isCloseable( final IPresentablePart toClose ) { return false; } public boolean isPartMoveable( final IPresentablePart toMove ) { return false; } public boolean isStackMoveable() { return false; } public void selectPart( final IPresentablePart toSelect ) { } public void setState( final int newState ) { } public boolean supportsState( final int state ) { return false; } }; /** * Extension Point ID of the StackPresentation Extension point. */ public static final String STACK_PRESENTATION_EXT_ID = "org.eclipse.rap.ui.stackPresentations"; /** * This method is used for getting the <code>{@link LayoutPart}</code> ID for * a specific <code>IStackPresentationSite</code>. Their is no other * oppertunity to get this id. * * @param site an instance of <code>IStackPreentationSite</code>. * * @return the unique <code>LayoutPart</code> ID defined in a Perspective or * <code>null</code> if their is no id. * * @see LayoutPart * @see IStackPresentationSite */ public static final String getLayoutPartId( final IStackPresentationSite site ) { String result = null; if( site != null && site instanceof DefaultStackPresentationSite ) { DefaultStackPresentationSite defaultSite = ( DefaultStackPresentationSite) site; result = defaultSite.getProperty( "id" ); } return result; } /** * Loads the saved <code>ConfigurableStack</code> id from the preferences * store using a specific <code>IStackPresentationSite</code>. This id is * needed to instantiate the <code>ConfigurableStack</code> for a specific * LayoutPart. * * @param site an instance of <code>IStackPreentationSite</code>. * * @return the saved <code>ConfigurableStack</code> id for the part * represented by the <code>IStackPresentationSite</code> or <code>null</code> * if no id is saved. * * @see LayoutPart * @see IStackPresentationSite */ public static String getSavedStackId( final IStackPresentationSite site ) { String layoutPartId = null; String result = IPreferenceStore.STRING_DEFAULT_DEFAULT; layoutPartId = getLayoutPartId( site ); if( layoutPartId != null ) { ScopedPreferenceStore prefStore = ( ScopedPreferenceStore )PrefUtil.getAPIPreferenceStore(); String stackPresentationId = ConfigurableStackProxy.STACK_PRESENTATION_ID; String stackPresentationKey = stackPresentationId + "/" + layoutPartId; result = prefStore.getString( stackPresentationKey ); } return result; } private ConfigurationAction configAction; private ImageDescriptor menuIcon; private Composite parent; private ConfigurableStackProxy proxy; private IStackPresentationSite site; private String stackPresentationId; private List managersWhoHasListeners; /** * Instantiate an object of this class by calling the super constructor with * a dummy <code>{@link IStackPresentationSite}</code>. * * @see IStackPresentationSite */ public ConfigurableStack() { super( siteDummy ); } public Control createPartToolBar() { Control result = null; IToolBarManager manager = getPartToolBarManager(); ConfigurationAction action = getConfigAction(); IStackPresentationSite site = getSite(); int actionCount = 0; if( action != null && manager != null ) { addPropertyChangeListenerToToolBar( manager ); IContributionItem[] items = manager.getItems(); String paneId = getPaneId( site ); // get the toolbar if( manager instanceof IToolBarManager2 ) { result = ( ( IToolBarManager2 ) manager ).getControl2(); } // set the correct visibility for( int i = 0; i < items.length; i++ ) { IContributionItem item = items[ i ]; boolean isVisible = action.isViewActionVisibile( paneId, item.getId() ); if( ( !item.isVisible() && isVisible ) || ( item.isVisible() && !isVisible ) ) { item.setVisible( isVisible ); } if( isVisible ) { actionCount++; } } // update the toolbar manager with the new visibility if( manager != null && result != null ) { manager.update( true ); } // if no item is visible the toolbar should be null if( actionCount <= 0 ) { result = null; } if( result != null ) { result.pack(); result.setVisible( true ); } } return result; } private void addPropertyChangeListenerToToolBar( final IToolBarManager manager ) { if( manager instanceof IToolBarManager2 && !hasListener( manager ) ) { final IToolBarManager2 manager2 = ( IToolBarManager2 ) manager; final IPropertyChangeListener listener = new IPropertyChangeListener() { public void propertyChange( final PropertyChangeEvent event ) { if( event.getProperty().equals( IToolBarManager2.PROP_LAYOUT ) ) { if( configAction != null ) { configAction.fireToolBarChange(); } } } }; manager2.addPropertyChangeListener( listener ); final Control toolBar = manager2.getControl2(); if( toolBar != null ) { // Remove all listeners from the manager and the manager from the list // to prevent memory leaks toolBar.addDisposeListener( new DisposeListener() { public void widgetDisposed( final DisposeEvent event ) { toolBar.removeDisposeListener( this ); manager2.removePropertyChangeListener( listener ); if( managersWhoHasListeners != null ) { managersWhoHasListeners.remove( manager ); } } } ); } } } private boolean hasListener( final IToolBarManager manager ) { boolean result = false; if( managersWhoHasListeners == null ) { managersWhoHasListeners = new ArrayList(); } if( managersWhoHasListeners.contains( manager ) ) { result = true; } else { managersWhoHasListeners.add( manager ); } return result; } public IPartMenu createViewMenu() { IPartMenu result = null; if( isPartMenuVisisble() ) { result = new IPartMenu() { public void showMenu(final Point location) { IPresentablePart selectedPart = site.getSelectedPart(); if( selectedPart instanceof PresentablePart ) { PresentablePart part = ( PresentablePart ) selectedPart; part.getPane().showViewMenu(location); } } }; } return result; } /** * Returns an instance of <code>{@link ConfigurationAction}</code> for this * <code>ConfigurableStack</code> object, which is declared over the same * extension. * * @return the <code>ConfigurationAction</code> or <code>null</code> if no * action is declared for the id holding by this object. * * @see ConfigurationAction */ public ConfigurationAction getConfigAction() { ConfigurationAction result = null; if( configAction == null ) { if( stackPresentationId != null && !stackPresentationId.equals( "" ) ) { IExtensionRegistry registry = Platform.getExtensionRegistry(); String stackId = STACK_PRESENTATION_EXT_ID; IExtensionPoint point = registry.getExtensionPoint( stackId ); if( point != null ) { IConfigurationElement[] elements = point.getConfigurationElements(); String defaultValue = IPreferenceStore.STRING_DEFAULT_DEFAULT; String actionClass = defaultValue; boolean breakValue = true; IConfigurationElement element = null; ImageDescriptor imageDesc = null; for( int i = 0; breakValue && i < elements.length; i++ ) { String id = elements[ i ].getAttribute( "id" ); if( id.equals( stackPresentationId ) ) { actionClass = elements[ i ].getAttribute( CONFIG_ACTION_NAME ); if( actionClass != null && !actionClass.equals( defaultValue ) ) { breakValue = false; element = elements[ i ]; String actionImage = element.getAttribute( "actionIcon" ); String menuImage = element.getAttribute( "menuIcon" ); String contributerId = element.getContributor().getName(); if( actionImage != null ) { imageDesc = AbstractUIPlugin.imageDescriptorFromPlugin( contributerId, actionImage ); } if( menuImage != null ) { menuIcon = AbstractUIPlugin.imageDescriptorFromPlugin( contributerId, menuImage ); } } } } String defaultStore = defaultValue; if( actionClass != null && !actionClass.equals( defaultStore ) && element != null ) { try { Object obj = element.createExecutableExtension( CONFIG_ACTION_NAME ); if( obj instanceof ConfigurationAction ) { configAction = ( ConfigurationAction ) obj; configAction.init( getSite(), this ); if( imageDesc != null ) { configAction.setImageDescriptor( imageDesc ); } } } catch( CoreException e ) { e.printStackTrace(); } } } } } result = configAction; return result; } /** * Represents the menuIcon which is declared in the extension for the * extension point org.eclipse.rap.ui.stackPresentations. Return the * ImageDescriptor for this image. */ protected ImageDescriptor getMenuIcon() { return menuIcon; } /** * This method returns the <code>{@link PartPane}</code> id defined in the * selected <code>{@link PresentablePart}</code> of a * <code>IStackPresentationSite</code> instance. * * @param site an instance of <code>IStackPresentationSite</code> * * @return the id of the <code>PartPane</code> from the selected * <code>PresentablePart</code> or an empty String if no part is selected. * * @see PartPane * @see PresentablePart * @see IStackPresentationSite */ public final String getPaneId( final IStackPresentationSite site ) { String result = ""; IPresentablePart selectedPart = site.getSelectedPart(); if( selectedPart instanceof PresentablePart ) { PresentablePart part = ( PresentablePart ) selectedPart; result = part.getPane().getID(); } return result; } private String getSecondaryPaneId( final IStackPresentationSite site ) { String result = null; IPresentablePart selectedPart = site.getSelectedPart(); if( selectedPart instanceof PresentablePart ) { PresentablePart part = ( PresentablePart ) selectedPart; PartPane pane = part.getPane(); if( pane instanceof ViewPane ) { ViewPane viewPane = ( ViewPane ) pane; result = viewPane.getViewReference().getSecondaryId(); } } return result; } /** * Returns the parent composite for this kind of <code>StackPresentation * </code>. * @return the parent composite */ public Composite getParent() { return parent; } /** * This method returns the <code>{@link IToolBarManager}</code> for the * selected <code>{@link ViewPart}</code>. * * @return the <code>IToolBarManager</code> or <code>null</code> if their is * no <code>ViewPart</code> selected. * * @see IToolBarManager * @see ViewPart */ public IToolBarManager getPartToolBarManager() { IToolBarManager result = null; IStackPresentationSite site = getSite(); String paneId = getPaneId( site ); IWorkbench workbench = PlatformUI.getWorkbench(); IWorkbenchWindow window = workbench.getActiveWorkbenchWindow(); IWorkbenchPage activePage = window.getActivePage(); if( activePage != null ) { String secId = getSecondaryPaneId( site ); IViewPart viewPart = null; if( secId != null ) { IViewReference ref = activePage.findViewReference( paneId, secId ); if( ref != null ) { viewPart = ( ViewPart ) ref.getPart( false ); } } else { viewPart = activePage.findView( paneId ); } IActionBars bars = null; if( viewPart != null ) { IViewSite viewSite = ( IViewSite ) viewPart.getSite(); bars = viewSite.getActionBars(); result = bars.getToolBarManager(); } } return result; } /** * If this Stack is from the type standaloneview, than it will have an * attribute called showTitle. This is a parameter of the crate method in the * original <code>AbstractPresentationFactory</code>. This is just a separate * method, because the creation is now automated and using proxy objects. * To match the old behaviour, this method was introduced. * @return the showTitle flag for the standalone view. If the view is not * standalone, it will return allways <code>false</code>. */ public boolean getShowTitle() { return proxy.getShowTitle(); } /** * Returns the <code>{@link IStackPresentationSite}</code> holding by this * instance. * * @return the site used for communication between the presentation and * the workbench. * * @see IStackPresentationSite */ public IStackPresentationSite getSite() { return site; } public String getStackPresentationId() { return stackPresentationId; } /** * Returns the type of the Stack. * @return the type. See <code>PresentationFactory</code> constants. */ protected String getType() { return proxy.getType(); } /** * This is called right after all necessary fields are initialized e.g. site, * stackPresentationId, parent and proxy. Subclasses can implement any * initializaion behaviour using this mehtod. */ public abstract void init(); /** * This method is called right after the constructor is called. It's * necessary for creating a <code>ConfigurableStack</code> object over an * extension because the standard <code>StackPresentation</code> has no * parameterless constructor. * <p> * This method just set the mandatory fields. * </p> * * @param site the site used for communication between the presentation and * the workbench. * @param stackId the StackPresentation ID, which is declared in the * Extension. * @param parent the parent composite to use for the presentation's controls. * @param proxy the <code>{@link ConfigurableStackProxy}</code> that holds * this instance. * * @see ConfigurableStackProxy * @see StackPresentation */ public void init( final IStackPresentationSite site, final String stackId, final Composite parent, final ConfigurableStackProxy proxy ) { this.site = site; this.stackPresentationId = stackId; this.parent = parent; this.proxy = proxy; init(); } private boolean isPartMenuVisisble() { boolean result = false; if( configAction != null ) { result = configAction.isPartMenuVisible(); } return result; } /** * Method to change the current StackPresentation of a part. This method just * calls the * <code>{@link ConfigurableStackProxy#setCurrentStackPresentation(String)} * </code> method. * * @param newStackId the id of the stack to change. * * @see ConfigurableStackProxy */ public void setCurrentStackPresentation( final String newStackId ) { if( proxy != null ) { proxy.setCurrentStackPresentation( newStackId ); } } }